///////////////////////////////////////////////////////////////////////////
// delegate.h
// Interface/implementation of the delegate classes and macros
///////////////////////////////////////////////////////////////////////////
// Author: Ryan Binns
// Changelog:
//     19-Aug-2003 : Initial Release
///////////////////////////////////////////////////////////////////////////

#ifndef DELEGATE_H__
#define DELEGATE_H__

// This STL include file removes the STL warning when the compiler
// is set to warning level 4. It was written by Oskar Wieland, and
// is available at:
// http://www.codeproject.com/vcpp/stl/stl_without_warnings.asp
#define STL_USING_VECTOR
#include "stl.h"

// Declares a delegate
// name - gives the beginning of the name of the delegate namespace, so
//        DECLARE_DELEGATE(Add, ..., ...) would make a namespace
//        called "AddDelegate" which contains the Add delegate classes.
// parmdecl - is the declaration of the parameters in the callbacks
//            (surrounded by brackets), such as "(int val1, int val2)"
// parmcall - is how the parameters are called (surrounded in brackets),
//            such as "(var1, var2)"
// so: DECLARE_DELEGATE(Add, (int val1, int val2), (val1, val2))
// would declare a delegate called AddDelegate, that takes two int
// parameters (the parameter names are not important).
#define DECLARE_DELEGATE(name, parmdecl, parmcall)								\
namespace name##Delegate														\
{																				\
	class Delegate;	/* Forward declaration */									\
	/* A function object base class for this parameter list */					\
	class Functor																\
	{																			\
	public:																		\
		virtual void Invoke parmdecl = 0;										\
		virtual bool isMethod() = 0;											\
		virtual bool operator ==(Functor *pf) = 0;								\
	};																			\
																				\
	/* Template class derived from Functor for									\
	   making class-specific function objects */								\
	template<class C>															\
	class TFunctor : public Functor												\
	{																			\
	public:																		\
		/* Only constructor - stores the given data */							\
		TFunctor(C* pObj, void (C::*pFunc)parmdecl)								\
		{																		\
			m_pObj = pObj;														\
			m_pFunc = pFunc;													\
		}																		\
		bool isMethod() { return true; }										\
		bool operator ==(Functor *pf)											\
		{																		\
			if(!pf->isMethod())													\
				return false;													\
			TFunctor<C> *pf1 = (TFunctor<C>*)pf;								\
			if((pf1->m_pObj == m_pObj) && (pf1->m_pFunc == m_pFunc))			\
				return true;													\
			else																\
				return false;													\
		}																		\
																				\
		/* Invokes the function object with the given parameters */				\
		void Invoke parmdecl	{ (m_pObj->*m_pFunc)parmcall; }					\
	private:																	\
		C *m_pObj;					/* Object pointer */						\
		void (C::*m_pFunc)parmdecl;	/* Method pointer */						\
	};																			\
																				\
	/* Class for function function objects */									\
	class FFunctor : public Functor												\
	{																			\
	public:																		\
		/* Only constructor - stores the given data */							\
		FFunctor(void (*pFunc)parmdecl) { m_pFunc = pFunc; }					\
		bool isMethod() { return false; }										\
		bool operator ==(Functor *pf)											\
		{																		\
			if(pf->isMethod())													\
				return false;													\
			FFunctor *pf1 = (FFunctor*)pf;										\
			if(pf1->m_pFunc == m_pFunc)											\
				return true;													\
			else																\
				return false;													\
		}																		\
																				\
		/* Invokes the function object with the given parameters */				\
		void Invoke parmdecl	{ m_pFunc parmcall; }							\
	private:																	\
		void (*m_pFunc)parmdecl;	/* Function pointer */						\
	};																			\
																				\
	/* Delegate class definition */												\
	class Delegate																\
	{																			\
	public:																		\
		Delegate() { };															\
		~Delegate()																\
		{																		\
			for(vit i=m_pFuncs.begin(); i!=m_pFuncs.end(); i++)					\
				delete (*i);													\
			m_pFuncs.clear();													\
		}																		\
																				\
		/* Template function for adding member function callbacks */			\
		template<class C>														\
		void Add(C *pObj, void (C::*pFunc)parmdecl)								\
		{																		\
			m_pFuncs.push_back(new TFunctor<C>(pObj, pFunc));					\
		}																		\
		/* Add a non-member (or static member) callback function */				\
		void Add(void (*pFunc)parmdecl)											\
		{																		\
			m_pFuncs.push_back(new FFunctor(pFunc));							\
		}																		\
		/* Template function for removing member function callbacks */			\
		template<class C>														\
		void Remove(C *pObj, void (C::*pFunc)parmdecl)							\
		{																		\
			TFunctor<C> f(pObj, pFunc);											\
			for(vit i=m_pFuncs.begin(); i!=m_pFuncs.end(); i++)					\
			{																	\
				if(*(*i) == &f)													\
				{																\
					delete *i;													\
					m_pFuncs.erase(i);											\
					break;														\
				}																\
			}																	\
		}																		\
		/* Removes a non-member (or static member) callback function */			\
		void Remove(void (*pFunc)parmdecl)										\
		{																		\
			FFunctor f(pFunc);													\
			for(vit i=m_pFuncs.begin(); i!=m_pFuncs.end(); i++)					\
			{																	\
				if(*(*i) == &f)													\
				{																\
					delete *i;													\
					m_pFuncs.erase(i);											\
					break;														\
				}																\
			}																	\
		}																		\
																				\
		/* Addition operators */												\
		void operator +=(Functor *pFunc)										\
		{																		\
			m_pFuncs.push_back(pFunc);											\
		}																		\
		void operator +=(void (*pFunc)parmdecl)									\
		{																		\
			m_pFuncs.push_back(new FFunctor(pFunc));							\
		}																		\
		/* Subtraction operators */												\
		void operator -=(Functor *pFunc)										\
		{																		\
			for(vit i=m_pFuncs.begin(); i!=m_pFuncs.end(); i++)					\
			{																	\
				if(*(*i) == pFunc)												\
				{																\
					delete *i;													\
					m_pFuncs.erase(i);											\
					break;														\
				}																\
			}																	\
			delete pFunc;														\
		}																		\
		void operator -=(void (*pFunc)parmdecl)									\
		{																		\
			Remove(pFunc);														\
		}																		\
																				\
		/* Calls all the callbacks in the callback list */						\
		void Invoke parmdecl													\
		{																		\
			for(vit i=m_pFuncs.begin(); i!=m_pFuncs.end(); i++)					\
				(*i)->Invoke parmcall;											\
		}																		\
		/* Calls all the callbacks in the callback list */						\
		void operator ()parmdecl	{ Invoke parmcall; }						\
																				\
	private:																	\
		/* List of callback functions */										\
		std::vector<Functor*>	m_pFuncs;										\
		/* typedef'd iterator */												\
		typedef std::vector<Functor*>::iterator vit;							\
	};																			\
}																				\
																				\
template<class C>																\
name##Delegate::TFunctor<C> *name##Handler(C *pObj, void (C::*pFunc)parmdecl)	\
{																				\
	return new name##Delegate::TFunctor<C>(pObj, pFunc);						\
}

#endif	// DELEGATE_H__